package com.ruicar.afs.cloud.product.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.log.annotation.SysLog;
import com.ruicar.afs.cloud.common.core.query.QueryCondition;
import com.ruicar.afs.cloud.common.core.security.util.SecurityUtils;
import com.ruicar.afs.cloud.common.core.uid.AfsSequenceGenerator;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import com.ruicar.afs.cloud.product.condition.ProductImplementeCondition;
import com.ruicar.afs.cloud.product.entity.*;
import com.ruicar.afs.cloud.product.enums.ProductOnlineStatus;
import com.ruicar.afs.cloud.product.enums.StatusType;
import com.ruicar.afs.cloud.product.enums.WorkflowTypeEnum;
import com.ruicar.afs.cloud.product.service.*;
import com.ruicar.afs.cloud.product.vo.ProductImplementePlanVo;
import com.ruicar.afs.cloud.product.vo.ProductImplementeVo;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.WorkFlowResponse;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.request.QueryFLowCmdRequest;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.request.StartFlowRequest;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.request.TaskSubmitRequest;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.response.FlowCmdBean;
import com.ruicar.afs.cloud.workflow.gwt.service.WorkflowService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author changyu.gui
 * @version 1.0
 * @date 2020/5/27 10:06
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/productImplemente")
@Api(value = "productImplemente", description = "产品上线")
public class ProductImplementeController {
    private final ProductImplementeService productImplementeService;
    private final ProductImplementePlanService productImplementePlanService;
    private final ProductPlanService productPlanService;
    private final WorkApproveRecordService workApproveRecordService;
    private final WorkflowService workflowService;//工作流
    private final WorkTaskCreatedService workTaskCreatedService;
    private final WorkTaskAssignService workTaskAssignService;
    private final AfsSequenceGenerator afsSequenceGenerator;

    @PostMapping(value = "/getProductLaunchList")
    @ApiOperation(value = "多条件分页获取产品上线信息数据")
    public IResponse<IPage<ProductImplemente>> getProductLaunchList(@RequestBody QueryCondition<ProductImplementeCondition> condition) {
        String startTime = null;
        String endTime = null;
        if (condition.getCondition().getStartTime() != null && condition.getCondition().getStartTime().length > 0) {
            startTime = condition.getCondition().getStartTime()[0];
            endTime = condition.getCondition().getStartTime()[1];
        }
        return IResponse.success(productImplementeService.page(new Page(condition.getPageNumber(), condition.getPageSize()), Wrappers.<ProductImplemente>query().lambda()
                .like(StringUtils.isNotEmpty(condition.getCondition().getOnlineNumber()), ProductImplemente::getOnlineNumber, condition.getCondition().getOnlineNumber())
                .like(StringUtils.isNotEmpty(condition.getCondition().getOnlineName()), ProductImplemente::getOnlineName, condition.getCondition().getOnlineName())
                .eq(StringUtils.isNotEmpty(condition.getCondition().getImplementeStatus()), ProductImplemente::getImplementeStatus, condition.getCondition().getImplementeStatus())
                .ge(StringUtils.isNotBlank(startTime),ProductImplemente::getCreateTime, startTime)
                .le(StringUtils.isNotBlank(endTime), ProductImplemente::getCreateTime,StringUtils.isNotBlank(endTime)? DateUtil.endOfDay(DateUtil.parse(endTime)):null)
                .orderByDesc(ProductImplemente::getCreateTime)
        ));
    }

    @PostMapping(value = "/save")
    @ApiOperation(value = "保存产品上线信息--初始保存")
    @Transactional(rollbackFor = Exception.class)
    public IResponse save(@RequestBody ProductImplementeCondition condition) {
        ProductImplemente implemente = condition;
        int count = productImplementeService.count(Wrappers.<ProductImplemente>query().lambda()
                .eq(ProductImplemente::getOnlineName, implemente.getOnlineName())
        );
        if (count > 0)
            return IResponse.fail("产品上线名称已存在！");
        if (implemente.getId() == null) {
            //获取编号
            Long seqno = afsSequenceGenerator.genNext(AfsEnumUtil.key(StatusType.PRODUCT_NUM_FASX), StatusType.PRODUCT_NUM_FASX.toString());
            String planNo = AfsEnumUtil.key(StatusType.PRODUCT_NUM_FASX) + DateUtil.year(DateUtil.date()) +StringUtils.leftPad(String.valueOf(seqno), 4, '0');// 编号
            implemente.setOnlineNumber(planNo);

            implemente.setImplementeStatus(AfsEnumUtil.key(StatusType.TOSUBMIT));
            productImplementeService.save(implemente);
        } else {
            ProductImplemente implementeHis = productImplementeService.getById(implemente.getId());
            productImplementeService.updateById(implemente);
            //修改状态
            if (!implementeHis.getImplementeStatus().equals(implemente.getImplementeStatus()))
                this.updateStatus(implemente, AfsEnumUtil.key(ProductOnlineStatus.TO_BE_REVIEWED));
        }
        return IResponse.success(implemente);
    }

    @PostMapping(value = "/saveProductPlanImplemente")
    @ApiOperation(value = "产品上线方案信息--初始保存")
    @Transactional(rollbackFor = Exception.class)
    public IResponse saveProductPlanImplemente(@RequestBody ProductImplementeCondition condition) {
        Long productImplementeId = condition.getId();
        List<ProductImplementePlan> list = productImplementePlanService.listByIds(Arrays.asList(condition.getIds()));
        if (list.size() > 0)
            return IResponse.fail("所选的产品方案已被选择");
        List<ProductImplementePlan> planList = new ArrayList<>();
        ProductImplementePlan productImplementePlan;
        String status = condition.getImplementeStatus();
        for (Long id : condition.getIds()) {
            productImplementePlan = new ProductImplementePlan(id, productImplementeId, status);
            //核对产品方案数据并修改状态
            check(productImplementePlan, AfsEnumUtil.key(ProductOnlineStatus.TO_BE_REVIEWED));
            planList.add(productImplementePlan);
        }
        if (planList.size() > 0)
            productImplementePlanService.saveOrUpdateBatch(planList);
        return IResponse.success(true);
    }
    @RequestMapping(value = "/delByImplementeId/{id}", method = RequestMethod.DELETE)
    @ApiOperation(value = "通过id删除上线信息")
    @Transactional(rollbackFor = Exception.class)
    public IResponse delByImplementeId(@PathVariable String id){
        //查询产品上线信息表
        ProductImplemente implemente = productImplementeService.getById(id);
        if(implemente==null) return IResponse.fail("产品上线信息不存在！");
        if(!AfsEnumUtil.key(StatusType.TOSUBMIT).equals(implemente.getImplementeStatus())) return IResponse.fail("产品上线状态不在待提交，不可删除！");
        List<ProductImplementePlan> list = productImplementePlanService.list(Wrappers.<ProductImplementePlan>query().lambda()
                .eq(ProductImplementePlan::getProductImplementeId, implemente.getId())
        );
        //删除
        productImplementePlanService.removeById(implemente);
        list.forEach(productPlanImplemente -> {
                    productPlanService.update(Wrappers.<ProductPlan>lambdaUpdate()
                            .eq(ProductPlan::getId, productPlanImplemente.getProductPlanId())
                            .set(ProductPlan::getStatus,  AfsEnumUtil.key(ProductOnlineStatus.TAKE_EFFECT))
                    );
            productImplementePlanService.removeById(productPlanImplemente);
        });
        productImplementeService.removeById(implemente);
        return  new IResponse<Boolean>().setData(true).setMsg("通过id删除成功！");
    }
    @RequestMapping(value = "/delById/{id}", method = RequestMethod.DELETE)
    @ApiOperation(value = "通过id删除产品方案上线信息")
    @Transactional(rollbackFor = Exception.class)
    @SysLog("通过id删除")
    public IResponse saveProductPlanImplemente(@PathVariable String id) {
        //查询
        ProductImplementePlan implemente = productImplementePlanService.getById(id);
        //判断
        if (implemente == null)
            return IResponse.fail("所选的产品方案已被删除了");
        //删除
        productImplementePlanService.removeById(implemente);
        //还原产品方案状态
        productPlanService.update(Wrappers.<ProductPlan>lambdaUpdate()
                .eq(ProductPlan::getStatus, AfsEnumUtil.key(ProductOnlineStatus.TO_BE_REVIEWED))
                .eq(ProductPlan::getId, implemente.getProductPlanId())
                .set(ProductPlan::getStatus, AfsEnumUtil.key(ProductOnlineStatus.TAKE_EFFECT)));
        return new IResponse<Boolean>().setData(true).setMsg("通过id删除成功！");
    }

    @PostMapping(value = "/getProposalApplicationInfo")
    @ApiOperation(value = "获取产品上线信息")
    public IResponse<ProductImplementeVo> getProposalApplicationInfo(@RequestBody ProductImplementeCondition condition) {
        //查询产品上线信息表
        ProductImplemente implemente = productImplementeService.getById(condition.getId());
        return IResponse.success(implemente);
    }

    @PostMapping(value = "/getProposalApplicationInfoTable")
    @ApiOperation(value = "获取上线的产品方案列表信息")
    public IResponse<ProductImplementeVo> getProposalApplicationInfoTable(@RequestBody ProductImplementeCondition condition) {
        //查询产品上线方案数据表
        IPage<List<ProductImplementePlanVo>> list = productImplementePlanService.queryPlanImplementeList(new Page(condition.getPageNumber(), condition.getPageSize()),condition.getId());
        return IResponse.success(list);
    }

    @SneakyThrows
    @PostMapping(value = "/saveProposalApplicationInfo")
    @ApiOperation(value = "产品上线信息--审批保存")
    @Transactional
    public IResponse saveProposalApplicationInfo(@RequestBody ProductImplementeCondition condition) {
        ProductImplemente productImplemente = productImplementeService.getById(condition.getId());

        //最终节点，修改产品方案状态
        if (condition.getIsFinalJudgment() && AfsEnumUtil.key(WorkflowTypeEnum.SUBMIT).equals(condition.getApproveSuggest())) {
            productImplementeService.update(Wrappers.<ProductImplemente>lambdaUpdate()
                    .eq(ProductImplemente::getId, productImplemente.getId())
                    .set(ProductImplemente::getImplementeStatus, AfsEnumUtil.key(StatusType.TOREVIEW))
            );
            productImplemente.setImplementeStatus(AfsEnumUtil.key(StatusType.TOREVIEW));
            this.updateStatus(productImplemente, AfsEnumUtil.key(ProductOnlineStatus.GO_ONLINE));

            //根据上传ID查询产品方案
            List<ProductImplementePlan> productImplementePlans = productImplementePlanService.list(Wrappers.<ProductImplementePlan>query().lambda()
                    .eq(ProductImplementePlan::getProductImplementeId, productImplemente.getId())
            );
            for(ProductImplementePlan productImplementePlan : productImplementePlans){
                productPlanService.sendAlterDealerMq(productImplementePlan.getProductPlanId());
            }
        }

        WorkTaskAssign assgin = workTaskAssignService.getOne(Wrappers.<WorkTaskAssign>query().lambda()
                        .eq(WorkTaskAssign::getBizDataId, productImplemente.getId().toString())
                        .eq(WorkTaskAssign::getUserName, SecurityUtils.getUsername())
                , false
        );
        WorkTaskCreated created = workTaskCreatedService.getOne(Wrappers.<WorkTaskCreated>query().lambda()
                        .eq(WorkTaskCreated::getBizDataId, productImplemente.getId().toString())
                , false
        );
        //提交完成之后删除其他人员代办
        List<WorkTaskAssign> assignList = workTaskAssignService.list(Wrappers.<WorkTaskAssign>query().lambda()
                .eq(WorkTaskAssign::getBizDataId, productImplemente.getId().toString())
        );
        TaskSubmitRequest taskSubmitRequest = new TaskSubmitRequest();
        taskSubmitRequest.setGwtUserId(assgin.getAssignId());
        taskSubmitRequest.setAfsFlowKey(created.getAfsFlowKey());
        taskSubmitRequest.setBizDataId(productImplemente.getDataId() + "");
        QueryFLowCmdRequest request = new QueryFLowCmdRequest();
        request.setFlowInstanceId(created.getFlowInstanceId());
        WorkFlowResponse<List<FlowCmdBean>> cmdResponse = workflowService.queryFlowCmd(request);
        List<FlowCmdBean> cmdList = cmdResponse.getAfsData();
        FlowCmdBean cmd = workTaskCreatedService.channelApprove(condition.getApproveSuggest(), cmdList);
        if (cmd != null) {
            log.info("==================================提交工作流开始==================================》");
            taskSubmitRequest.setCmdId(cmd.getId());
            ObjectMapper mapper = new ObjectMapper();
            //获取配置节点信息
            String json = mapper.writeValueAsString(productImplemente);
            JSONObject cancelJson = JSONObject.parseObject(json);
            workflowService.taskSubmit(taskSubmitRequest, cancelJson);

            //删除剩余节点数据信息
            for (int i = 0; i < assignList.size(); i++) {
                workTaskAssignService.removeById(assignList.get(i).getId().toString());
            }

            //保存审批记录
            WorkApproveRecord record = new WorkApproveRecord();
            record.setApproveSuggest(condition.getApproveSuggest());//审批意见
            record.setApproveRemark(condition.getApprovalRemarks());//审批备注
            record.setDisposeNode(created.getNodeId());//审批节点
            record.setDisposeNodeName(created.getTaskName());//节点名称
            record.setDisposeStaff(SecurityUtils.getUsername());//审批人员
            record.setApproveEndTime(DateUtil.date());//审批结束时间
            record.setProductNo(productImplemente.getId().toString());//审批编号
            record.setUseScene(AfsEnumUtil.key(WorkflowTypeEnum.PRODUCT_LAUNCH));//审批场景
            record.setStageId(productImplemente.getId());//流程实例ID
            workApproveRecordService.save(record);
        }
        return new IResponse<ProductImplemente>().setData(productImplemente);
    }

    @SneakyThrows
    @PostMapping(value = "/processSubmission")
    @ApiOperation(value = "产品上线信息--流程开始")
    @SysLog("产品上线信息提交")
    @Transactional(rollbackFor = Exception.class)
    public IResponse processSubmission(@RequestBody ProductImplementeCondition condition) {

        //修改流程状态
        ProductImplemente implemente =  productImplementeService.getById(condition.getId());
        if (implemente.getId() == null)
            return IResponse.fail("产品上线请保存！");

        List<ProductImplementePlan> list = productImplementePlanService.list(Wrappers.<ProductImplementePlan>query().lambda()
                .eq(ProductImplementePlan::getProductImplementeId, implemente.getId())
        );
        if (list.size() == 0)
            return IResponse.fail("无产品方案不可提交！");
        int count = productImplementeService.count(Wrappers.<ProductImplemente>query().lambda()
                .eq(ProductImplemente::getOnlineNumber, implemente.getOnlineNumber())
                .ne(ProductImplemente::getId, implemente.getId())
        );
        if (count > 0)
            return IResponse.fail("产品上线编号已存在！");
        ProductImplemente implementeHis = productImplementeService.getById(implemente.getId());
        if (!AfsEnumUtil.key(StatusType.TOSUBMIT).equals(implementeHis.getImplementeStatus()))
            return IResponse.fail("产品上线编号已在流程中！");
        implemente.setImplementeStatus(AfsEnumUtil.key(StatusType.INREVIEW));
        productImplementeService.updateById(implemente);

        //修改产品流程状态
        if (!implementeHis.getImplementeStatus().equals(implemente.getImplementeStatus()))
            this.updateStatus(implemente, AfsEnumUtil.key(ProductOnlineStatus.UNDER_REVIEW));
        //发起流程
        /** 1、组装流程实例 */
        StartFlowRequest startFlowNew = new StartFlowRequest();
        startFlowNew.setAfsFlowKey(AfsEnumUtil.key(WorkflowTypeEnum.PRODUCT_LAUNCH));//塞入afs内部映射key
        startFlowNew.setFlowName((StringUtils.isEmpty(implemente.getOnlineNumber())?"":(implemente.getOnlineNumber())+"-")+AfsEnumUtil.desc(WorkflowTypeEnum.PRODUCT_LAUNCH));//塞入流程名称
        startFlowNew.setBizDataId(implemente.getId().toString());//业务主键
        /** 2、组装业务数据 */
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(implemente);
        JSONObject cancelJson = JSONObject.parseObject(json);
        /** 3、正式发起流程 */
        workflowService.startWorkFlow(startFlowNew, cancelJson);

        //保存审批记录
        WorkApproveRecord record = new WorkApproveRecord();
        record.setApproveSuggest("submit");//审批意见
        record.setApproveRemark(condition.getApprovalRemarks());//审批备注
        record.setDisposeNodeName("开始");//节点名称
        record.setDisposeStaff(SecurityUtils.getUsername());//审批人员
        record.setApproveEndTime(DateUtil.date());//审批结束时间
        record.setProductNo(implemente.getId().toString());//审批编号
        record.setUseScene(AfsEnumUtil.key(WorkflowTypeEnum.PRODUCT_LAUNCH));//审批场景
        workApproveRecordService.save(record);

        return new IResponse<Boolean>().setData(true).setMsg("流程提交成功！");

    }

    //更改状态
    private void check(ProductImplementePlan productImplementePlan, String status) {
        ProductPlan productPlan = productPlanService.getById(productImplementePlan.getProductPlanId());
        if (!AfsEnumUtil.key(ProductOnlineStatus.TAKE_EFFECT).equals(productPlan.getStatus()) && !AfsEnumUtil.key(ProductOnlineStatus.TO_BE_REVIEWED).equals(productPlan.getStatus())) {
            log.error("产品方案有误，编号：{}", productPlan.getProductNumber());
            throw new AfsBaseException("产品方案有误，编号：" + productPlan.getProductNumber());
        }
        productPlan.setStatus(status);
        productPlanService.updateById(productPlan);
    }

    //修改审批状态
    private void updateStatus(ProductImplemente implemente, String satus) {
        List<ProductImplementePlan> list = productImplementePlanService.list(Wrappers.<ProductImplementePlan>query().lambda()
                .eq(ProductImplementePlan::getProductImplementeId, implemente.getId())
        );
        list.forEach(productPlanImplemente -> {
                    productPlanService.update(Wrappers.<ProductPlan>lambdaUpdate()
                            .eq(ProductPlan::getId, productPlanImplemente.getProductPlanId())
                            .set(ProductPlan::getStatus, satus)
                    );
                }
        );
    }


}
